package net.qiqbframework.modelling.command;


import lombok.Getter;
import net.qiqbframework.commandhandling.CommandBus;
import net.qiqbframework.commandhandling.CommandHandlerNotFoundException;
import net.qiqbframework.commandhandling.CommandMessage;
import net.qiqbframework.commandhandling.CommandMessageHandler;
import net.qiqbframework.common.Registration;
import net.qiqbframework.common.lock.LockFactory;
import net.qiqbframework.common.lock.PessimisticLockFactory;
import net.qiqbframework.common.lock.TopicLock;
import net.qiqbframework.messaging.annotation.*;
import net.qiqbframework.messaging.task.CurrentMessageTask;
import net.qiqbframework.modelling.command.fetching.AggregateCommandModel;
import net.qiqbframework.modelling.command.fetching.PreAnnotatedCommand;
import net.qiqbframework.modelling.command.fetching.PreAnnotatedCommandModel;
import net.qiqbframework.modelling.command.handling.BusinessMessage;
import net.qiqbframework.modelling.command.handling.BusinessMessageExecutableHandler;
import net.qiqbframework.modelling.command.handling.GenericBusinessMessage;
import net.qiqbframework.modelling.domain.*;
import net.qiqbframework.modelling.repository.AggregateRepository;
import net.qiqbframework.serialization.SerializedObject;
import net.qiqbframework.serialization.Serializer;

import java.util.*;
import java.util.function.Function;

/**
 * 内部注解处理
 *
 * @param <C>
 * @param <A>
 */
public class InnerAnnotationCommandHandler<C, A> implements CommandMessageHandler {

    private final Class<C> commandType;

    private AggregateCommandModel<C, A> aggregateCommandModel;

    private final AggregateRepository<A> repository;

    private final AggregateCommandHandler aggregateCommandHandler;


    @Getter
    private final AggregateModel<A> aggregateModel;


    private final AggregateHandlingMonitor aggregateHandlingMonitor;

    private final Serializer aggregateRootSerializer;
    private final HandlerParameterResolverFactory parameterResolverFactory;
    private final MessageHandlingMemberFactory handlerDefinition;
   //private LockFactory lockFactory = PessimisticLockFactory.usingDefaults();
    protected InnerAnnotationCommandHandler(InnerAnnotationCommandHandlerBuilder<C, A> builder) {

        builder.validate();

        this.repository = builder.repository;
        this.commandType = builder.commandType;
        this.aggregateHandlingMonitor = builder.aggregateHandlingMonitor();
        this.aggregateRootSerializer = builder.aggregateRootSerializer();

        this.handlerDefinition = builder.handlerDefinition;
        this.parameterResolverFactory = builder.parameterResolverFactory;

        AggregateModel<A> aggregateModel = builder.buildAggregateModel();
        this.aggregateModel = aggregateModel;
        this.aggregateCommandModel = new PreAnnotatedCommandModel<>(commandType, repository, parameterResolverFactory, handlerDefinition);
        this.aggregateCommandHandler = new AggregateCommandHandler();
        initializeHandlers();

    }


    public Registration subscribe(CommandBus commandBus) {

        return commandBus.subscribe(aggregateCommandModel.commandName(), aggregateCommandHandler);
    }

    private void initializeHandlers() {
        AnnotatedHandlerInspector<C> inspector = AnnotatedHandlerInspector.inspectType(commandType,
                parameterResolverFactory,
                HandlerAttributesPostProcessor.EMPTY,
                handlerDefinition);
        // 汇总多个执行器
        for (Map.Entry<Class<?>, SortedSet<MessageExecutableHandler>> handlersPerType : inspector.getAllHandlers().entrySet()) {

            for (MessageExecutableHandler handler : handlersPerType.getValue()) {
                initializeHandler(handler);
            }
        }

    }


    private void initializeHandler(MessageExecutableHandler handler) {

        handler.unwrap(BusinessMessageExecutableHandler.class).ifPresent(cmh -> {
            aggregateCommandHandler.addBusinessMessageExecutableHandler(cmh);
        });

    }

    @Override
    public Object handle(CommandMessage<?> commandMessage) throws Exception {

        if (aggregateCommandHandler == null) {
            throw new CommandHandlerNotFoundException(commandMessage);
        }
        return aggregateCommandHandler.handle(commandMessage);
    }


    private class AggregateCommandHandler implements CommandMessageHandler {

        private final List<BusinessMessageExecutableHandler> handlers = new ArrayList<>();

        public void addBusinessMessageExecutableHandler(BusinessMessageExecutableHandler handler) {
            this.handlers.add(handler);
        }

        @Override
        public Object handle(CommandMessage<?> commandMessage) throws Exception {
            // 创建命令
            PreAnnotatedCommand<C, A> command = new PreAnnotatedCommand<>((C) commandMessage.getPayload(), aggregateCommandModel);

            final Optional<Aggregate<A>> aggregateOptional = command.obtainAggregate();
            Aggregate<A> aggregate;
            if (aggregateOptional.isPresent()) {
                aggregate = aggregateOptional.get();
                CurrentMessageTask.get().getOrComputeResource("_lastAggregate", (Function<String, Object>) s -> aggregateOptional.get());
            } else {
                final Object _lastAggregate = CurrentMessageTask.get().getResource("_lastAggregate");
                if (_lastAggregate != null) {
                    if (_lastAggregate instanceof Aggregate lastAggregate && lastAggregate.aggregateName().equals(aggregateModel.modelName())) {
                        aggregate = lastAggregate;
                    } else {
                        aggregate = null;
                    }
                } else {
                    aggregate = null;
                }
                if (aggregate == null){
                    throw new AggregateNotFoundException(null, "命令聚合根生成器中获取聚合根对象为空");
                }

            }
            //TopicLock lock = lockFactory.obtainLock(aggregate.identifierAsString());
            //CurrentMessageTask.get().onCleanup(u -> lock.release());

            final Map<BizIdentifierModel<?>, Object> bizIdentifiers = aggregateModel.getBizIdentifiers(aggregate.aggregateRoot());

            // 验证加载的聚合对象的业务ID是否和命令的加载凭证都一致，如果不一致，则报错
            for (BizIdentifierVoucherMember subBizIdentifierMember : command.allBizIdentifierVoucherMembers()) {
                final Object commandSubBizId = subBizIdentifierMember.getValue();
                final String commandSubBizIdName = subBizIdentifierMember.getBizIdentifierName();
                if (!commandSubBizId.equals(bizIdentifiers.get(aggregateModel.getBizIdentifierModel(commandSubBizIdName)))) {
                    throw new IllegalArgumentException("业务ID不匹配");
                }
            }
            // 进行虚拟化
            final SerializedObject<byte[]> beforeHandleSerialize = aggregateRootSerializer.serialize(aggregate.aggregateRoot(), byte[].class);
            final A beforeHandleSnapshot = aggregateRootSerializer.deserialize(beforeHandleSerialize);
            aggregateHandlingMonitor.beforeHandle(commandMessage, beforeHandleSnapshot);
            // 调用命令自身方法
            BusinessMessage<A> businessMessage = GenericBusinessMessage.of(aggregate.aggregateRoot());
            if (aggregate instanceof AggregateLifecycle aggregateLifecycle) {
                aggregateLifecycle.execute(() -> {
                    try {
                        for (BusinessMessageExecutableHandler handler : handlers) {
                            handler.handle(businessMessage, commandMessage.getPayload());
                        }

                    } catch (Exception e) {
                        if (e instanceof RuntimeException runtimeException){
                            throw runtimeException;
                        }
                        throw new RuntimeException(e);
                    }
                });
            } else {
                for (BusinessMessageExecutableHandler handler : handlers) {
                    handler.handle(businessMessage, commandMessage.getPayload());
                }
            }


            final SerializedObject<byte[]> afterHandleSerialize = aggregateRootSerializer.serialize(aggregate.aggregateRoot(), byte[].class);
            final A afterHandlSnapshot = aggregateRootSerializer.deserialize(afterHandleSerialize);
            // 添加快照
            CurrentMessageTask.get().afterCommit((t) -> {
                aggregateHandlingMonitor.afterCommit(commandMessage, beforeHandleSnapshot, afterHandlSnapshot, aggregate);
            });
            return null;
        }


    }
}
